/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.session.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.inspur.edp.bef.core.session.BefBizContext;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;

public class BefBizContextJsonDeSerializer extends JsonDeserializer<BefBizContext> {
    static ObjectMapper mapper = new ObjectMapper();
    static JavaTimeModule module = new JavaTimeModule();
    static {
        mapper.registerModule(module);
    }
    @Override
    public BefBizContext deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        BefBizContext befBizContext = new BefBizContext();
        SerializerUtils.readStartObject(jsonParser);


        while(jsonParser.getCurrentToken() == JsonToken.FIELD_NAME) {
            String propName = SerializerUtils.readPropertyName(jsonParser);
            this.readPropertyValue(befBizContext, propName, jsonParser);
        }

        SerializerUtils.readEndObject(jsonParser);
        return befBizContext;
    }

    private void readPropertyValue(BefBizContext befBizContext, String propName, JsonParser jsonParser) {
        switch (propName) {
            case BefBizContextConst.ID:
                befBizContext.setId(SerializerUtils.readPropertyValue_String(jsonParser));
                break;
            case BefBizContextConst.CreationDate:{
                try {
                    ZonedDateTime time = mapper.readValue(jsonParser, ZonedDateTime.class);
                    befBizContext.setCreationDate (time);
                    jsonParser.nextToken();
                } catch (IOException e) {
                    throw new RuntimeException("解析业务上下文创建日期报错");
                }
                finally {
                    break;
                }
            }
            case BefBizContextConst.Items:
                befBizContext.getItems().putAll(readObject(SerializerUtils.readPropertyValue_String(jsonParser)));
                break;
            case BefBizContextConst.ParentId:
                befBizContext.setParentId(SerializerUtils.readPropertyValue_String(jsonParser));
                break;
            case BefBizContextConst.SessionID:
                befBizContext.setSessionId(SerializerUtils.readPropertyValue_String(jsonParser));
                break;
            default:
                throw new RuntimeException("未识别的属性:" + propName);
        }
    }

    private Map<String, Object> readObject(String jsonText){
        String splitOperator1 = "!@";
        String splitOperator2 = "!:";
        if(StringUtils.isEmpty(jsonText))
            return null;
        Map<String, Object> map = new HashMap<>();
        String[] array = jsonText.split(splitOperator2);
        for(String item : array){
            String[] keyValue = item.split(splitOperator1);
            String key = keyValue[0];
            String value = keyValue[1];
            String dataType = String.valueOf(value.charAt(0));
            String actValue = value.substring(1);
            DataTypeEnum dataTypeEnum = DataTypeEnum.forValue(dataType);
            map.put(key, getValue(actValue, dataTypeEnum));
        }
        return map;
    }

    private Object getValue(String value, DataTypeEnum dataTypeEnum){
        switch (dataTypeEnum){
            case None:
                return null;
            case BoolType:
                return Boolean.valueOf(value);
            case CharType:
                return value.charAt(0);
            case StringType:
                return value;
            case IntegerType:
                return Integer.valueOf(value);
            case ShortType:
                return Short.valueOf(value);
            case LongType:
                return Long.valueOf(value);
            case FloatType:
                return Float.valueOf(value);
            case DoubleType:
                return Double.valueOf(value);
            case ObjType:
                return decodeBase64(value);
        }
        return "";
    }

    private Object decodeBase64(String json){
        Object obj = null;
        byte[] bytes = Base64Utils.deCode(json);
        ByteArrayInputStream memoryInStream = new ByteArrayInputStream(bytes);
        try {
            ObjectInputStream ois = new ObjectInputStream(memoryInStream);
            obj =ois.readObject();
            ois.close();
            memoryInStream.close();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }
}
